package com.heima.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.search.dtos.UserSearchDto;
import com.heima.model.search.pojos.ApUserSearch;
import com.heima.model.search.vos.SearchArticleVo;
import com.heima.model.threadlocal.AppThreadLocalUtils;
import com.heima.model.user.pojos.ApUser;
import com.heima.search.service.ApUserSearchService;
import com.heima.search.service.ArticleSearchService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class ArticleSearchServiceImpl implements ArticleSearchService {

    //构建索引库名称常量
    public static final String INDEX_NAME="app_info_article";

    @Autowired
    RestHighLevelClient restHighLevelClient;

    @Autowired
    ApUserSearchService apUserSearchService;

    /**
     * 根据文章分页搜素
     * @param dto
     * @return
     */
    @Override
    public ResponseResult search(UserSearchDto dto) {

        //检查关键字不能为空
        if(StringUtils.isBlank(dto.getSearchWords())){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"搜索关键词不能为空");
        }
        //如果分页大小为0,设为10
        int pageSize = dto.getPageSize();
        if(pageSize==0){
            pageSize=10;
        }

            //搜索首页,0代表搜索首页,需要记录搜索记录
        if(dto.getFromIndex()==0){
            //提前获取threadlocal登录用户
            ApUser user = AppThreadLocalUtils.getUser();
            dto.setEntryId(user == null ? null : user.getId());// 当前登录用户ID
            //在搜索出结果前,异步保存搜索记录
            apUserSearchService.insert(dto);
        }


        //1.构建搜索请求
        SearchRequest searchRequest = new SearchRequest("");

        // 构建所有请求参数SearchSourceBuilder 构建所有请求参数
        SearchSourceBuilder builder = new SearchSourceBuilder();
        // 构建query请求
        // 构建布尔的请求参数
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            // 通过 must 加入  按照match分词查询 title字段条件
        boolQueryBuilder.must(QueryBuilders.matchQuery("title",dto.getSearchWords()));
            // 通过 filter 加入  发布时间小于最小时间  range条件(filter不含分词查询)
        boolQueryBuilder.filter(QueryBuilders.rangeQuery("publishTime").lt(dto.getMinBehotTime()));
        builder.query(boolQueryBuilder);

        // 构建highlight请求
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        // 设置 title 字段高亮
        highlightBuilder.field("title");
            // 前置标签<span style标签>
        highlightBuilder.preTags("<span style='red:color'>");
            // 后置标签</>标签
        highlightBuilder.postTags("</span>");
        builder.highlighter(highlightBuilder);

        // 构建sort排序 设置按照发布时间 降序排序
        builder.sort("publishTime", SortOrder.DESC);

        // 设置分页参数 from(0) + size (pageSize)
        builder.from(0); //filter从最小时间分页,默认给0
        builder.size(pageSize);

        //所有条件放入搜索请求中
        searchRequest.source(builder);

        //创建vo集合
        List<SearchArticleVo> searchArticleVos = new ArrayList<>();
        // 2. 调用客户端执行搜索请求 得到 SearchResponse响应对象
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 3. 解析响应的结果
            // 得到命中结果
            SearchHits hits = searchResponse.getHits();
            // 得到文档结果列表
            SearchHit[] hits1 = hits.getHits();
            // 得到文章文档的json字符串
            for (SearchHit hit : hits1) {
                String articleJson = hit.getSourceAsString();
                //封装文章实体类
                SearchArticleVo searchArticleVo = JSON.parseObject(articleJson,SearchArticleVo.class);
                // 获取高亮结果
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                // title的高亮结果
                HighlightField highlightField = highlightFields.get("title");
                // 拼接所有高亮片段，得到完整的高亮处理结果  高亮结果数组
                String highlightResult = StringUtils.join(highlightField.getFragments());
                searchArticleVo.setTitle(highlightResult);
                // 封装到集合中
                searchArticleVos.add(searchArticleVo);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR,"搜索出现异常");
        }
        return ResponseResult.okResult(searchArticleVos);
    }
}
